Skip to content

[improvement](be) Implement native Parquet decoding for FileScannerV2#65674

Open
Gabriel39 wants to merge 16 commits into
apache:masterfrom
Gabriel39:codex/fix-file-scanner-v2-native-decode
Open

[improvement](be) Implement native Parquet decoding for FileScannerV2#65674
Gabriel39 wants to merge 16 commits into
apache:masterfrom
Gabriel39:codex/fix-file-scanner-v2-native-decode

Conversation

@Gabriel39

@Gabriel39 Gabriel39 commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

What problem does this PR solve?

Issue Number: None

Related PR: None

Problem Summary:

FileScannerV2 previously used Arrow RecordReader/arrays/builders for Parquet value materialization and reconstructed complex columns through intermediate decoded objects. That path duplicated decode/materialization work, retained fragmented per-batch scratch, amplified string and nested-column memory usage, and made adaptive batches and cache/profile behavior diverge from the legacy v1 reader.

This PR implements an independent native Parquet read path under format_v2:

  • Decodes Parquet page V1/V2 definition/repetition levels and value streams without Arrow value readers.
  • Supports PLAIN, RLE/bit-packed dictionary indices, RLE booleans, DELTA_BINARY_PACKED, DELTA_LENGTH_BYTE_ARRAY, DELTA_BYTE_ARRAY, and BYTE_STREAM_SPLIT.
  • Keeps Decoder responsible for raw physical streams while DataTypeSerDe owns physical/logical conversion and direct append into final Doris columns.
  • Materializes dictionaries once into typed Doris state, validates every dictionary ID, and supports dictionary-filter index paths without rebuilding string values for rejected rows.
  • Reconstructs ARRAY/MAP/STRUCT shape from levels while leaf values go directly into Doris child columns; levels-only scans do not materialize payload values.
  • Reuses persistent normal-size decode, null-map, binary, selection, and level scratch; releases exceptional nested-batch allocations above a 4 MiB per-buffer high-water mark after parent offsets/null maps are consumed.
  • Uses a page-fragment hybrid selection path for highly selective scans: enter DataTypeSerDe once, then let each concrete encoding bulk-gather or batch-decode/compact selected values while advancing and validating the complete physical stream.
  • Keeps NULL-interleaving on the cursor-preserving fallback path and exposes HybridSelectionBatches, HybridSelectionRanges, and HybridSelectionNullFallbackBatches for diagnosis.
  • Aligns selection, adaptive batch sizing, footer/page cache, MergeRange behavior, and profiling counters with v1.
  • Removes the obsolete ParquetLeafBatch, PhysicalToLogicalConverter, Arrow builder/value-reader, and Arrow RecordReader fallback contracts from the v2 value path.
  • Leaves FE and the legacy be/src/format v1 implementation unchanged.

Arrow is now limited to the existing metadata/index/probe adapter boundary; it is not used to materialize scan values.

Release note

FileScannerV2 Parquet scans now use native Doris page/encoding decoding and direct DataTypeSerDe materialization instead of Arrow value readers.

Check List (For Author)

  • Test: Unit Test
    • Validation through commit d257ca06abf: remote ASAN BE build passed; targeted BE UT passed 91/91; LLVM 16 format check passed.
    • Commit 099c111c12f adds hybrid sparse decoding and decoder UT coverage. Build/UT validation was not run at the user's request; CI is requested below.
  • Behavior changed: Yes. FileScannerV2 Parquet values and levels use the native Doris decoder. Sparse non-null selections are decoded once per page fragment. Unsupported physical/logical/encoding combinations return explicit errors instead of falling back to Arrow value materialization.
  • Does this need documentation: Yes. Updated docs/file-scanner-v2-parquet-scan-design.md and docs/file-scanner-v2-code-review-guide.md.

@hello-stephen

Copy link
Copy Markdown
Contributor

Thank you for your contribution to Apache Doris.
Don't know what should be done next? See How to process your PR.

Please clearly describe your PR:

  1. What problem was fixed (it's best to include specific error reporting information). How it was fixed.
  2. Which behaviors were modified. What was the previous behavior, what is it now, why was it modified, and what possible impacts might there be.
  3. What features were added. Why was this function added?
  4. Which code was refactored and why was this part of the code refactored?
  5. Which functions were optimized and what is the difference before and after the optimization?

@Gabriel39

Copy link
Copy Markdown
Contributor Author

run buildall

@Gabriel39

Copy link
Copy Markdown
Contributor Author

/review

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated review completed. I found one issue in the FileScannerV2 Parquet reader changes: persistent scratch now extends Arrow binary chunk lifetimes after materialization/discard.\n\nValidation: static review only. git diff --check c8b81647776bcd482b99665530f9fd5ba41f0d03...0826614aff1d8bf5e21b78f8c8c5a0acfcb465de passed. I did not run build or unit/regression tests in this review-only checkout.

Comment thread be/src/format_v2/parquet/reader/scalar_column_reader.cpp Outdated
@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-H: Total hot run time: 29482 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpch-tools
Tpch sf100 test result on commit 0826614aff1d8bf5e21b78f8c8c5a0acfcb465de, data reload: false

------ Round 1 ----------------------------------
============================================
q1	17953	4121	4119	4119
q2	2099	343	212	212
q3	10238	1404	837	837
q4	4686	477	348	348
q5	7512	855	591	591
q6	194	172	142	142
q7	757	844	636	636
q8	10287	1537	1632	1537
q9	6281	4376	4368	4368
q10	6856	1735	1469	1469
q11	498	343	323	323
q12	711	559	419	419
q13	18166	3367	2790	2790
q14	271	272	240	240
q15	q16	791	777	722	722
q17	977	990	856	856
q18	7156	5742	5460	5460
q19	1173	1289	1095	1095
q20	756	657	530	530
q21	5622	2644	2491	2491
q22	421	351	297	297
Total cold run time: 103405 ms
Total hot run time: 29482 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	4359	4296	4301	4296
q2	281	327	219	219
q3	4613	4930	4402	4402
q4	2050	2164	1375	1375
q5	4384	4229	4268	4229
q6	226	180	128	128
q7	1995	2021	1638	1638
q8	2487	2167	2126	2126
q9	7755	7748	7699	7699
q10	4685	4650	4231	4231
q11	555	410	502	410
q12	761	754	535	535
q13	3245	3589	3019	3019
q14	299	300	290	290
q15	q16	718	737	652	652
q17	1361	1344	1320	1320
q18	8105	7303	6916	6916
q19	1139	1091	1086	1086
q20	2220	2200	1944	1944
q21	5254	4559	4389	4389
q22	519	472	415	415
Total cold run time: 57011 ms
Total hot run time: 51319 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 176989 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpcds-tools
TPC-DS sf100 test result on commit 0826614aff1d8bf5e21b78f8c8c5a0acfcb465de, data reload: false

query5	4339	621	485	485
query6	503	215	197	197
query7	4948	606	343	343
query8	344	191	177	177
query9	8758	3983	3983	3983
query10	449	349	287	287
query11	5905	2344	2135	2135
query12	154	104	101	101
query13	1286	619	448	448
query14	6279	5214	4884	4884
query14_1	4234	4223	4228	4223
query15	211	205	181	181
query16	1002	464	426	426
query17	1103	695	555	555
query18	2423	464	336	336
query19	203	197	148	148
query20	114	108	105	105
query21	235	157	128	128
query22	13538	13533	13310	13310
query23	17339	16402	16056	16056
query23_1	16147	16182	16191	16182
query24	7494	1756	1264	1264
query24_1	1304	1286	1285	1285
query25	552	461	380	380
query26	1351	341	207	207
query27	2608	629	382	382
query28	4507	1994	1980	1980
query29	1075	641	502	502
query30	344	259	225	225
query31	1121	1102	981	981
query32	104	62	64	62
query33	533	322	246	246
query34	1169	1129	619	619
query35	769	777	681	681
query36	1178	1182	1008	1008
query37	161	112	93	93
query38	1888	1700	1655	1655
query39	877	875	869	869
query39_1	837	826	841	826
query40	251	173	140	140
query41	72	68	69	68
query42	100	92	93	92
query43	319	321	284	284
query44	1454	770	744	744
query45	190	180	170	170
query46	1121	1204	736	736
query47	2171	2114	2027	2027
query48	399	427	297	297
query49	568	418	309	309
query50	1147	406	325	325
query51	10474	10754	10782	10754
query52	89	81	72	72
query53	247	269	206	206
query54	299	241	218	218
query55	76	70	64	64
query56	310	275	269	269
query57	1337	1266	1196	1196
query58	281	250	234	234
query59	1587	1643	1440	1440
query60	292	281	266	266
query61	150	147	154	147
query62	537	497	423	423
query63	239	202	208	202
query64	2806	1031	861	861
query65	4769	4642	4679	4642
query66	1802	507	363	363
query67	28705	29272	28963	28963
query68	3417	1512	1002	1002
query69	425	307	261	261
query70	1061	960	904	904
query71	335	318	285	285
query72	3086	2691	2377	2377
query73	789	788	422	422
query74	5065	4931	4700	4700
query75	2526	2512	2145	2145
query76	2343	1184	751	751
query77	345	391	269	269
query78	11903	11844	11414	11414
query79	1371	1208	763	763
query80	865	524	441	441
query81	504	330	285	285
query82	592	159	119	119
query83	396	319	288	288
query84	284	153	123	123
query85	989	576	498	498
query86	416	288	268	268
query87	1851	1824	1754	1754
query88	3695	2750	2769	2750
query89	529	364	330	330
query90	1772	203	194	194
query91	200	188	160	160
query92	62	63	58	58
query93	1601	1532	969	969
query94	649	367	323	323
query95	786	493	442	442
query96	1008	800	376	376
query97	2602	2634	2482	2482
query98	211	205	203	203
query99	1103	1123	980	980
Total cold run time: 262445 ms
Total hot run time: 176989 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
ClickBench: Total hot run time: 25.08 s
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/clickbench-tools
ClickBench test result on commit 0826614aff1d8bf5e21b78f8c8c5a0acfcb465de, data reload: false

query1	0.01	0.01	0.01
query2	0.10	0.05	0.04
query3	0.26	0.14	0.14
query4	1.61	0.14	0.14
query5	0.24	0.22	0.22
query6	1.25	1.05	1.06
query7	0.04	0.00	0.00
query8	0.06	0.04	0.04
query9	0.37	0.33	0.31
query10	0.56	0.54	0.54
query11	0.20	0.14	0.14
query12	0.18	0.15	0.14
query13	0.48	0.47	0.49
query14	1.02	1.01	1.00
query15	0.63	0.60	0.58
query16	0.32	0.31	0.33
query17	1.10	1.14	1.12
query18	0.22	0.21	0.22
query19	2.05	1.95	1.90
query20	0.01	0.01	0.01
query21	15.44	0.20	0.13
query22	4.93	0.05	0.06
query23	16.13	0.31	0.13
query24	2.92	0.42	0.34
query25	0.11	0.06	0.05
query26	0.73	0.21	0.15
query27	0.05	0.04	0.04
query28	3.54	0.93	0.53
query29	12.47	4.11	3.31
query30	0.29	0.16	0.18
query31	2.78	0.61	0.31
query32	3.22	0.58	0.49
query33	3.13	3.22	3.20
query34	15.76	4.19	3.52
query35	3.52	3.50	3.52
query36	0.56	0.45	0.43
query37	0.10	0.06	0.07
query38	0.06	0.04	0.04
query39	0.04	0.04	0.03
query40	0.17	0.16	0.15
query41	0.09	0.03	0.04
query42	0.04	0.03	0.03
query43	0.04	0.03	0.04
Total cold run time: 96.83 s
Total hot run time: 25.08 s

@Gabriel39
Gabriel39 marked this pull request as ready for review July 16, 2026 00:14
@Gabriel39
Gabriel39 requested a review from yiguolei as a code owner July 16, 2026 00:14
Gabriel39 added a commit to Gabriel39/incubator-doris that referenced this pull request Jul 16, 2026
### What problem does this PR solve?

Issue Number: None

Related PR: apache#65674

Problem Summary: FileScannerV2 retained Arrow binary and dictionary chunks in persistent Parquet reader scratch after synchronous Doris materialization. Large binary batches could therefore stay alive until a later read and overlap the next Arrow builder allocation. Release batch payload ownership on every success and error path while retaining vector capacity, clear borrowed StringRef scratch before its owners are released, and add unit coverage for ownership release and capacity reuse. Also remove the previous decoder changes under the legacy format directory so the v1 implementation remains unchanged; future native decoder work is constrained to format_v2.

This lifecycle fix addresses the review finding but does not claim to eliminate the separate complex-column temporary materialization overhead. That v2-only decoder/materializer redesign remains distinct from COUNT(nullable_col) pushdown.

### Release note

None

### Check List (For Author)

- Test: Unit Test
    - Remote ASAN BE build
    - 16 focused Parquet v2 BE unit tests
    - Remote clang-format check
    - Remote clang-tidy attempted; blocked by existing diagnostics and the remote toolchain missing stddef.h during analysis
- Behavior changed: No; internal buffer ownership is released earlier
- Does this need documentation: Yes; updated the FileScannerV2 Parquet design document and format_v2 review guide
@Gabriel39

Copy link
Copy Markdown
Contributor Author

run buildall

@Gabriel39

Copy link
Copy Markdown
Contributor Author

/review

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review summary

Changes requested for one P1 memory-lifecycle regression. The allocation-reuse work is otherwise coherent, and the earlier Arrow-chunk ownership issue is fixed at the current head, but persistent nested scratch still lacks a bounded high-water release policy. See the inline comment.

Checkpoint conclusions

  • Goal and proof: The PR reduces FileScannerV2/Parquet allocation and materialization overhead and hardens several reader boundaries. The changed tests cover logical reset, object/capacity reuse, Arrow-owner release, dictionary validation, column mapping, and split Row Group accounting, but they do not prove that oversized nested scratch is released; that missing property is the finding.
  • Scope: The scanner, mapper, reader, statistics, Iceberg, tests, and design/guidance changes are focused on the stated optimization/hardening work.
  • Concurrency: Row Group reader trees are uniquely owned and invoked serially by the scanner; no new shared globals, locks, atomics, lock ordering, or reentrant access was found.
  • Lifecycle: Arrow chunks and borrowed StringRefs now unwind safely on success/error paths, resolving the existing thread. However, Doris-owned nested value/null/conversion/level/index backing allocations remain until Row Group teardown; the inline P1 covers this distinct defect.
  • Configuration: No configuration items or dynamic-reload behavior are added.
  • Compatibility: No storage-format, wire-protocol, symbol, or rolling-upgrade contract changes were found. Required-slot mapping is populated from the scan tuple for finalized and late-filter expressions, so removing the invalid ordinal fallback is safe.
  • Parallel paths: Parquet, ORC, text, JSON/native layout consumers continue to use stable local_positions; Scanner retains residual evaluation after lazy materialization. Dictionary, selection/page-skip, nested values/levels-only, List/Map/Struct, and Iceberg delete paths were also traced.
  • Conditions and errors: New slot/dictionary/selection validation returns checked errors; malformed partial reader state is terminal rather than retried. No speculative defensive continuation was introduced.
  • Test coverage: Unit coverage is broad for the changed local behaviors, including negative dictionary/selection cases, but needs the oversized repeated-value retained-allocation regression test requested inline.
  • Test results: No generated expected-result file changed. This review was static-only because the review contract prohibits builds in this runner.
  • Observability: Existing Status context and profile counters are sufficient for these local changes; Row Group candidate totals are corrected per Split and no new critical metric/log path is required.
  • Transactions and persistence: Not applicable; no transaction, EditLog, replay, or persistent metadata behavior changes.
  • Data writes: Not applicable; scan-side decoding and equality-delete filtering do not alter write atomicity or crash recovery.
  • FE/BE variables: No new transmitted variable or protocol field is introduced.
  • Performance: Normal-size scratch reuse removes hot-path allocations, but child-count-unbounded nested buffers can accumulate outlier high-water capacity and cause a new memory-limit failure. Other reviewed CPU/I/O/allocation paths showed no substantiated regression.
  • Other issues / user focus: No additional review focus was supplied. After three normal plus risk-focused convergence rounds, no second valuable finding or unresolved suspicious point remains.

Validation state

The live head is 913123e6cfeaa5712fd9571006a92e87f177f5a7. The author reports a remote ASAN build and focused unit tests, but I did not independently run them. Current formatter, license, FE UT, and Cloud UT checks pass. COMPILE, BE UT, and performance fail during CI setup because this head conflicts with current master in be/test/format_v2/parquet/parquet_reader_control_test.cpp; those jobs did not reach compilation/tests, and the PR is currently marked conflicting.

Comment thread be/src/format_v2/parquet/reader/parquet_leaf_reader.h Outdated
### What problem does this PR solve?

Issue Number: None

Related PR: None

Problem Summary: FileScannerV2 currently materializes Parquet values through Arrow and repeatedly allocates conversion and nested-column scratch. Introduce an Arrow-independent physical column schema and selection-aware flat decode contract in the existing Doris Parquet kernel, batch string materialization, retain scalar and complex-reader scratch across batches, and document the target shared-level-plan interface for native complex decoding. The legacy v1 production call path remains unchanged.

### Release note

None

### Check List (For Author)

- Test: Unit Test
    - Remote ASAN BE build
    - 120 targeted Parquet BE unit tests
- Behavior changed: No; this adds migration interfaces and internal allocation optimizations
- Does this need documentation: Yes; updated the FileScannerV2 Parquet design document and format_v2 review guide
### What problem does this PR solve?

Issue Number: None

Related PR: apache#65674

Problem Summary: FileScannerV2 retained Arrow binary and dictionary chunks in persistent Parquet reader scratch after synchronous Doris materialization. Large binary batches could therefore stay alive until a later read and overlap the next Arrow builder allocation. Release batch payload ownership on every success and error path while retaining vector capacity, clear borrowed StringRef scratch before its owners are released, and add unit coverage for ownership release and capacity reuse. Also remove the previous decoder changes under the legacy format directory so the v1 implementation remains unchanged; future native decoder work is constrained to format_v2.

This lifecycle fix addresses the review finding but does not claim to eliminate the separate complex-column temporary materialization overhead. That v2-only decoder/materializer redesign remains distinct from COUNT(nullable_col) pushdown.

### Release note

None

### Check List (For Author)

- Test: Unit Test
    - Remote ASAN BE build
    - 16 focused Parquet v2 BE unit tests
    - Remote clang-format check
    - Remote clang-tidy attempted; blocked by existing diagnostics and the remote toolchain missing stddef.h during analysis
- Behavior changed: No; internal buffer ownership is released earlier
- Does this need documentation: Yes; updated the FileScannerV2 Parquet design document and format_v2 review guide
### What problem does this PR solve?

Issue Number: None

Related PR: apache#65674

Problem Summary: FileScannerV2 materialized ordinary Parquet values through Arrow arrays and temporary nested batches, which added allocation, conversion, and peak-memory overhead compared with the v1 reader. Route ordinary predicate and output columns through a persistent native reader that decodes directly into Doris columns, preserves selection and page-index coordinates, shares v1-compatible footer/page caches and MergeRange I/O, and keeps Arrow only for metadata planning, dictionary probing, and the existing COUNT complex levels-only path. Add detailed native decode profiles, adaptive-batch fragmentation profiles, complex/string/decimal/fixed-binary coverage, and update the Parquet design and review guidance. No FE or COUNT pushdown behavior is changed, and no be/src/format decoder code is modified.

### Release note

Improve FileScannerV2 Parquet scan memory use and native decode performance for scalar and complex columns.

### Check List (For Author)

- Test: Unit Test
    - 192 format v2 Parquet BE unit tests on the designated remote host
- Behavior changed: Yes (ordinary FileScannerV2 Parquet values use native direct materialization; query results and pushdown semantics are unchanged)
- Does this need documentation: Yes (design and review guide updated in this change)
### What problem does this PR solve?

Issue Number: close #xxx

Related PR: apache#65674

Problem Summary: The Parquet v2 native scan path no longer uses the prototype Arrow value-reader hierarchy, but its decoded leaf batch, nested load/build/consume protocol, factories, and tests remained reachable from a shape-only aggregate path. Remove that intermediate layer and isolate the unchanged COUNT(nullable_col) level-reading compatibility path behind a narrow API. Ordinary scans now expose only the persistent native read/skip/select contract.

### Release note

None

### Check List (For Author)

- Test: Unit Test (remote validation pending)
- Behavior changed: No
- Does this need documentation: Yes (updated in this commit)
### What problem does this PR solve?

Issue Number: None

Related PR: apache#65674

Problem Summary: FileScannerV2 still paid for an Arrow-decoded value layer or decoder-owned logical conversion before constructing Doris columns. This duplicated buffers for strings and nested values, amplified adaptive-batch memory peaks, and made dictionary, page-cache, and decode profiles difficult to compare with the v1 reader. Introduce an independent Parquet page/encoding reader under format_v2 whose decoders only parse encoded streams and own cursors. DataTypeSerDe now interprets Parquet physical and logical annotations and materializes selected values directly into persistent Doris columns. The native reader supports the existing scalar, decimal, date/time, timestamp, UUID, dictionary, delta, byte-stream-split, Page V1/V2, nested level, selection, page-index, footer/page-cache, and MergeRange paths. COUNT complex columns use a levels-only reader with persistent scratch, and page/decode/cache profiles expose cumulative deltas without duplicate counting. Arrow remains only in metadata/index planning and test fixture generation. No FE code or v1 format decoder is modified.

### Release note

Improve FileScannerV2 Parquet scan memory use and native decode performance, especially for strings, decimals, nested columns, dictionary selection, and adaptive batch sizes.

### Check List (For Author)

- Test: Unit Test
    - 14 Parquet decoder and DataTypeSerDe tests on the designated remote host
    - 76 Parquet v2 reader, selection, page-index, complex-column, and scan tests on the designated remote host
    - 6 focused COUNT/profile tests on the designated remote host
- Behavior changed: Yes (FileScannerV2 Parquet data pages materialize through the native v2 decoder and DataTypeSerDe; query semantics are unchanged)
- Does this need documentation: Yes (updated the FileScannerV2 Parquet design and review guide)
@Gabriel39
Gabriel39 force-pushed the codex/fix-file-scanner-v2-native-decode branch from 913123e to 78678d9 Compare July 16, 2026 11:36
### What problem does this PR solve?

Issue Number: None

Related PR: apache#65674

Problem Summary: Split the Parquet v2 decoder factory by encoding family and replace raw allocations with std::make_unique. This keeps decoder construction behavior unchanged while satisfying function-size and ownership static-analysis rules.

### Release note

None

### Check List (For Author)

- Test: Unit Test
    - Remote ASAN BE build and 90 Parquet v2/SerDe unit tests
    - Remote clang-tidy on the changed decoder factory
- Behavior changed: No
- Does this need documentation: No
### What problem does this PR solve?

Issue Number: None

Related PR: apache#65674

Problem Summary: Persistent Parquet v2 leaf readers reused level, null, selection, conversion, and dictionary-index scratch across batches. A legal repeated column can expand one logical batch into an exceptional number of leaf values, so staggered outliers could retain large allocations in multiple leaves until Row Group teardown. Keep normal-size capacity reusable, recursively release individual scratch buffers above a 4 MiB high-water mark after the top-level complex reader consumes the level plan, and cover the retained-capacity drop with a unit test.

### Release note

None

### Check List (For Author)

- Test: Unit Test
    - Remote ASAN ./build.sh --be
    - Remote Parquet v2 and SerDe unit-test suite
- Behavior changed: No
- Does this need documentation: Yes. Updated the FileScannerV2 Parquet design and review guide.
@Gabriel39 Gabriel39 changed the title [improvement](be) Optimize FileScannerV2 Parquet decoding [improvement](be) Implement native Parquet decoding for FileScannerV2 Jul 16, 2026
@Gabriel39

Copy link
Copy Markdown
Contributor Author

run buildall

@Gabriel39

Copy link
Copy Markdown
Contributor Author

/review

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review summary

Changes requested for 15 new, non-duplicate issues in the native Parquet reader. They cluster in three boundaries: shared footer/page-cache identity and immutability; exact decoder/page/level validation; and ARRAY/MAP/STRUCT shape preservation. The earlier Arrow-chunk ownership issue is fixed, and the existing nested-scratch high-water P1 remains active without being duplicated here.

Checkpoint conclusions

  • Goal and proof: The PR substantially implements native decoding and removes the old intermediate value path, but the current tests do not prove safe behavior for valid Page V1 BIT_PACKED levels, cache-order/version changes, decoder reuse, or several malformed-page/nested-shape cases covered by the inline findings.
  • Scope: The production, test, and design changes are focused on the stated FileScannerV2 Parquet migration, though the migration is broad enough that cache, decoder, selection, COUNT, and complex-column boundaries all needed end-to-end tracing.
  • Concurrency: Concurrent scans can share a cached FileMetaData; post-publication assign_ids() mutates it without synchronization. No other new lock-order or thread-entry issue was substantiated.
  • Lifecycle: Footer metadata is both option-dependent and mutated after publication; native S3 page keys lose the split's stable version; the reused delta-length decoder keeps stale/uninitialized state on empty pages. The existing nested-scratch retention thread remains separate.
  • Configuration: No new configuration item is added, but existing VARBINARY/TIMESTAMPTZ mapping options affect parsed schema and are missing from the shared footer-cache identity.
  • Compatibility: No storage or wire format is changed, but valid Page V1 BIT_PACKED definition/repetition levels are not supported by the non-bulk cursor paths, so existing files can fail or execute undefined behavior.
  • Parallel paths: Page V1/V2, compressed/uncompressed and cache-hit reads, selected/filtered/skipped values, normal nested scans and COUNT, v1/v2 footer-cache producers, and MAP/STRUCT sibling paths were checked. The findings identify the parallel instances that need the same exact validation.
  • Conditions and errors: Several decoder return values/counts are discarded, signed external sizes reach unsafe arithmetic/buffers, a malformed BYTE_STREAM_SPLIT payload reaches DORIS_CHECK, and release-only DCHECKs stand in for required corruption statuses.
  • Test coverage: Happy-path coverage is broad, but negative tests are missing for truncated BOOLEAN/delta/level streams, page-size and V2-level layout corruption, empty reused delta-length pages, null/misaligned MAPs, short siblings, leading continuations, and cache-order/version behavior. A concurrent same-footer cache test and valid BIT_PACKED Page V1 tests are also needed.
  • Test results: No generated regression .out file changed. The author reports remote ASAN build/focused-unit/format validation in the PR history; I did not independently run builds or tests under this review contract.
  • Observability: No new metric is required for these local failures; checked corruption statuses with file/column/page context are preferable to silent success, undefined behavior, or process termination.
  • Transactions and persistence: Not applicable; this is scan-side parsing/decoding and cache state, with no EditLog, replay, or transaction change.
  • Data writes: Not applicable; no table-data write, publish, or crash-recovery path is modified.
  • FE/BE variables: No new FE-to-BE transmitted variable or protocol field is introduced.
  • Performance: The native/materialization design removes intended allocations and copies, but correctness and bounded lifecycle must hold first. The existing P1 already covers retained outlier scratch; no additional non-duplicate performance regression was found.
  • Other issues / user focus: No extra user focus was supplied. After three normal/risk convergence rounds, the 15 inline findings below are the complete current non-duplicate set.

Validation state

The reviewed live head is d257ca06abff17c3a43f6f287594dc8dcf52ef80. This was static review only: the supplied contract prohibits builds, and this checkout has no .worktree_initialized, thirdparty/installed, or thirdparty/installed/bin/protoc.

Comment thread be/src/format_v2/parquet/parquet_file_context.cpp Outdated
Comment thread be/src/format_v2/parquet/parquet_file_context.cpp Outdated
Comment thread be/src/format_v2/parquet/reader/native/page_reader.cpp Outdated
Comment thread be/src/format_v2/parquet/reader/native/level_decoder.h Outdated
Comment thread be/src/format_v2/parquet/reader/native/bool_rle_decoder.cpp Outdated
Comment thread be/src/format_v2/parquet/reader/native/column_reader.cpp
Comment thread be/src/format_v2/parquet/reader/native/column_reader.cpp Outdated
Comment thread be/src/format_v2/parquet/reader/native/column_reader.cpp Outdated
Comment thread be/src/format_v2/parquet/reader/native/column_reader.cpp Outdated
Comment thread be/src/format_v2/parquet/reader/native/delta_bit_pack_decoder.h Outdated
@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-H: Total hot run time: 29697 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpch-tools
Tpch sf100 test result on commit d257ca06abff17c3a43f6f287594dc8dcf52ef80, data reload: false

------ Round 1 ----------------------------------
============================================
q1	17679	4132	4104	4104
q2	2044	351	197	197
q3	10261	1477	868	868
q4	4683	479	360	360
q5	7493	916	571	571
q6	198	190	144	144
q7	811	897	614	614
q8	9376	1626	1573	1573
q9	5602	4396	4336	4336
q10	6779	1753	1497	1497
q11	515	365	343	343
q12	745	586	465	465
q13	18136	3454	2720	2720
q14	270	278	247	247
q15	q16	794	785	716	716
q17	1018	1115	1002	1002
q18	7141	5788	5564	5564
q19	1314	1373	1085	1085
q20	810	695	626	626
q21	5994	2630	2359	2359
q22	435	365	306	306
Total cold run time: 102098 ms
Total hot run time: 29697 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	4474	4403	4449	4403
q2	316	347	231	231
q3	4628	4962	4411	4411
q4	2202	2229	1403	1403
q5	4530	4348	4405	4348
q6	240	184	134	134
q7	2295	2043	1764	1764
q8	2901	2377	2334	2334
q9	8228	7909	7958	7909
q10	4714	4694	4240	4240
q11	598	433	401	401
q12	775	780	563	563
q13	3343	3632	2878	2878
q14	298	297	269	269
q15	q16	728	738	655	655
q17	1434	1526	1360	1360
q18	8155	7406	7351	7351
q19	1146	1071	1090	1071
q20	2247	2228	1928	1928
q21	5393	4779	4555	4555
q22	542	503	419	419
Total cold run time: 59187 ms
Total hot run time: 52627 ms

### What problem does this PR solve?

Issue Number: None

Related PR: apache#65674

Problem Summary: Highly selective Parquet v2 scans entered DataTypeSerDe and the encoding decoder once per selection run. Fragmented selections therefore amplified virtual dispatch, consumer construction, and cursor-management overhead. Add a page-fragment hybrid selection plan that enters SerDe once and lets each native encoding batch gather or compact selected values while preserving and validating the full physical cursor. Add profile counters, decoder coverage, scratch retention bounds, and design/review documentation.

### Release note

None

### Check List (For Author)

- Test: No test run (per user request)
- Behavior changed: Yes (sparse Parquet v2 materialization is batched per page fragment)
- Does this need documentation: Yes (included in this PR)
@Gabriel39

Copy link
Copy Markdown
Contributor Author

run buildall

@Gabriel39

Copy link
Copy Markdown
Contributor Author

/review

@hello-stephen

Copy link
Copy Markdown
Contributor

BE UT Coverage Report

Increment line coverage 74.15% (5841/7877) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 57.54% (24181/42023)
Line Coverage 41.41% (238954/577095)
Region Coverage 37.24% (189108/507842)
Branch Coverage 38.30% (84753/221296)

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-H: Total hot run time: 29840 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpch-tools
Tpch sf100 test result on commit 1b19694cbea327acd4eab1dc9fe285e6e83bb79b, data reload: false

------ Round 1 ----------------------------------
============================================
q1	17656	4120	4113	4113
q2	2054	333	211	211
q3	10291	1443	865	865
q4	4687	477	344	344
q5	7529	890	582	582
q6	182	178	145	145
q7	786	861	648	648
q8	9358	1529	1629	1529
q9	5586	4346	4374	4346
q10	6769	1758	1497	1497
q11	524	354	333	333
q12	738	582	462	462
q13	18139	3473	2805	2805
q14	267	270	245	245
q15	q16	790	788	718	718
q17	1064	1079	948	948
q18	7065	5945	5602	5602
q19	1190	1311	1084	1084
q20	791	691	606	606
q21	5736	2710	2459	2459
q22	430	362	298	298
Total cold run time: 101632 ms
Total hot run time: 29840 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	4384	4313	4322	4313
q2	287	319	218	218
q3	4616	4972	4381	4381
q4	2069	2139	1356	1356
q5	4438	4286	4302	4286
q6	236	179	133	133
q7	1744	2143	1734	1734
q8	2597	2183	2206	2183
q9	8104	8131	7824	7824
q10	4702	4674	4309	4309
q11	582	439	389	389
q12	748	772	537	537
q13	3323	3607	2905	2905
q14	290	301	283	283
q15	q16	710	720	633	633
q17	1398	1348	1451	1348
q18	7909	7439	7420	7420
q19	1190	1118	1151	1118
q20	2223	2211	1925	1925
q21	5242	4522	4414	4414
q22	527	470	420	420
Total cold run time: 57319 ms
Total hot run time: 52129 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 178306 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpcds-tools
TPC-DS sf100 test result on commit 1b19694cbea327acd4eab1dc9fe285e6e83bb79b, data reload: false

query5	4341	630	503	503
query6	467	234	223	223
query7	4956	631	336	336
query8	343	200	170	170
query9	8805	4129	4149	4129
query10	496	355	302	302
query11	5844	2323	2178	2178
query12	166	102	107	102
query13	1272	603	416	416
query14	6353	5265	4928	4928
query14_1	4616	4234	4294	4234
query15	210	208	185	185
query16	1036	484	494	484
query17	1125	705	583	583
query18	2706	482	353	353
query19	215	197	160	160
query20	114	112	106	106
query21	238	173	140	140
query22	13521	13452	13360	13360
query23	17506	16590	16102	16102
query23_1	16272	16303	16306	16303
query24	7539	1806	1300	1300
query24_1	1300	1323	1307	1307
query25	586	476	396	396
query26	1343	383	228	228
query27	2433	622	388	388
query28	4360	2011	2010	2010
query29	1082	632	506	506
query30	347	270	228	228
query31	1121	1101	989	989
query32	112	62	63	62
query33	521	327	254	254
query34	1188	1130	655	655
query35	770	783	678	678
query36	1203	1205	1065	1065
query37	161	116	138	116
query38	1861	1693	1648	1648
query39	874	894	851	851
query39_1	841	830	850	830
query40	241	166	142	142
query41	67	63	66	63
query42	94	100	91	91
query43	331	343	290	290
query44	1441	769	764	764
query45	200	185	181	181
query46	1048	1157	722	722
query47	2085	2115	1969	1969
query48	395	430	301	301
query49	573	422	319	319
query50	1065	447	348	348
query51	10607	10667	10620	10620
query52	94	86	73	73
query53	268	285	204	204
query54	290	231	248	231
query55	75	76	66	66
query56	302	286	291	286
query57	1314	1263	1181	1181
query58	302	270	264	264
query59	1630	1673	1416	1416
query60	333	271	252	252
query61	148	143	150	143
query62	540	500	428	428
query63	232	202	199	199
query64	2787	1043	889	889
query65	4724	4614	4672	4614
query66	1775	509	379	379
query67	29301	29252	29023	29023
query68	3114	1427	1010	1010
query69	411	304	274	274
query70	1077	970	1009	970
query71	391	336	319	319
query72	3070	2688	2380	2380
query73	886	785	408	408
query74	5068	4915	4692	4692
query75	2541	2520	2136	2136
query76	2317	1214	804	804
query77	355	367	284	284
query78	11919	11839	11284	11284
query79	1478	1128	761	761
query80	1310	566	468	468
query81	527	342	302	302
query82	616	157	121	121
query83	368	324	303	303
query84	288	160	135	135
query85	974	592	523	523
query86	433	293	282	282
query87	1845	1821	1762	1762
query88	3770	2806	2789	2789
query89	442	377	330	330
query90	2010	206	199	199
query91	204	195	161	161
query92	60	62	53	53
query93	1728	1527	1047	1047
query94	714	348	343	343
query95	781	602	483	483
query96	1026	858	371	371
query97	2656	2613	2484	2484
query98	216	207	205	205
query99	1082	1127	965	965
Total cold run time: 264475 ms
Total hot run time: 178306 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
ClickBench: Total hot run time: 25.17 s
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/clickbench-tools
ClickBench test result on commit 1b19694cbea327acd4eab1dc9fe285e6e83bb79b, data reload: false

query1	0.01	0.00	0.00
query2	0.10	0.04	0.05
query3	0.26	0.16	0.13
query4	1.61	0.14	0.14
query5	0.25	0.24	0.23
query6	1.24	1.07	1.07
query7	0.04	0.01	0.01
query8	0.05	0.03	0.03
query9	0.40	0.32	0.31
query10	0.57	0.56	0.59
query11	0.19	0.14	0.13
query12	0.18	0.13	0.14
query13	0.47	0.49	0.50
query14	1.02	0.99	1.00
query15	0.62	0.63	0.59
query16	0.30	0.32	0.32
query17	1.12	1.15	1.10
query18	0.23	0.21	0.22
query19	2.13	1.99	1.97
query20	0.02	0.01	0.01
query21	15.47	0.20	0.13
query22	4.85	0.06	0.05
query23	16.13	0.31	0.12
query24	2.96	0.42	0.34
query25	0.12	0.05	0.04
query26	0.72	0.20	0.14
query27	0.04	0.04	0.04
query28	3.55	0.98	0.54
query29	12.51	4.15	3.32
query30	0.26	0.15	0.16
query31	2.77	0.57	0.31
query32	3.22	0.59	0.49
query33	3.13	3.18	3.20
query34	15.57	4.14	3.52
query35	3.53	3.55	3.58
query36	0.54	0.43	0.42
query37	0.09	0.07	0.06
query38	0.06	0.03	0.03
query39	0.03	0.04	0.03
query40	0.17	0.16	0.16
query41	0.09	0.03	0.03
query42	0.04	0.03	0.03
query43	0.04	0.04	0.03
Total cold run time: 96.7 s
Total hot run time: 25.17 s

@hello-stephen

Copy link
Copy Markdown
Contributor

BE Regression && UT Coverage Report

Increment line coverage 81.74% (6422/7857) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 75.56% (30978/40998)
Line Coverage 60.13% (344858/573565)
Region Coverage 57.07% (290929/509735)
Branch Coverage 58.41% (129350/221438)

@Gabriel39

Copy link
Copy Markdown
Contributor Author

run buildall

@Gabriel39

Copy link
Copy Markdown
Contributor Author

/review

@github-actions

Copy link
Copy Markdown
Contributor

Codex automated review failed and did not complete.

Error: Selected model is at capacity. Please try a different model.
Workflow run: https://github.com/apache/doris/actions/runs/29595389233

Please inspect the workflow logs and rerun the review after the underlying issue is resolved.

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-H: Total hot run time: 29480 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpch-tools
Tpch sf100 test result on commit 51c1f992647811ab0222edad2935131f445aaf33, data reload: false

------ Round 1 ----------------------------------
============================================
q1	17700	4054	4091	4054
q2	2015	320	198	198
q3	10303	1423	832	832
q4	4689	466	339	339
q5	7566	849	551	551
q6	197	178	136	136
q7	735	810	611	611
q8	9960	1566	1699	1566
q9	5956	4334	4339	4334
q10	6773	1719	1449	1449
q11	514	351	329	329
q12	748	580	446	446
q13	18171	3307	2777	2777
q14	265	262	247	247
q15	q16	787	775	709	709
q17	1037	981	952	952
q18	6761	5625	5486	5486
q19	1759	1321	1101	1101
q20	813	676	580	580
q21	5799	2646	2488	2488
q22	435	351	295	295
Total cold run time: 102983 ms
Total hot run time: 29480 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	4457	4355	4355	4355
q2	287	307	215	215
q3	4554	4995	4412	4412
q4	2027	2124	1365	1365
q5	4442	4275	4251	4251
q6	234	175	125	125
q7	1717	2144	1708	1708
q8	2500	2161	2258	2161
q9	7816	7802	7723	7723
q10	4687	4684	4211	4211
q11	599	433	366	366
q12	930	753	531	531
q13	3224	3532	3011	3011
q14	302	300	297	297
q15	q16	733	731	630	630
q17	1340	1297	1345	1297
q18	8086	7401	7253	7253
q19	1160	1094	1123	1094
q20	2225	2216	1932	1932
q21	5153	4528	4357	4357
q22	503	457	426	426
Total cold run time: 56976 ms
Total hot run time: 51720 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 177428 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpcds-tools
TPC-DS sf100 test result on commit 51c1f992647811ab0222edad2935131f445aaf33, data reload: false

query5	4316	641	469	469
query6	473	231	203	203
query7	4851	584	336	336
query8	367	194	172	172
query9	8774	4095	4057	4057
query10	469	382	294	294
query11	5955	2330	2104	2104
query12	156	103	101	101
query13	1253	628	434	434
query14	6266	5179	4850	4850
query14_1	4239	4225	4219	4219
query15	217	216	185	185
query16	1011	479	439	439
query17	1077	717	582	582
query18	2430	474	360	360
query19	211	194	153	153
query20	113	108	104	104
query21	228	157	137	137
query22	13557	13548	13296	13296
query23	17294	16380	16085	16085
query23_1	16192	16239	16230	16230
query24	7581	1787	1275	1275
query24_1	1305	1301	1290	1290
query25	559	471	390	390
query26	1334	340	218	218
query27	2660	591	372	372
query28	4435	2020	2001	2001
query29	1082	618	496	496
query30	351	269	230	230
query31	1133	1091	993	993
query32	109	64	64	64
query33	547	329	263	263
query34	1184	1120	645	645
query35	766	795	691	691
query36	1196	1158	1036	1036
query37	158	111	95	95
query38	1859	1708	1669	1669
query39	891	882	842	842
query39_1	832	854	838	838
query40	254	171	177	171
query41	69	62	67	62
query42	90	90	89	89
query43	325	334	279	279
query44	1439	775	761	761
query45	193	183	170	170
query46	1076	1218	698	698
query47	2126	2065	2058	2058
query48	400	376	299	299
query49	589	423	304	304
query50	1132	425	323	323
query51	11184	10778	11040	10778
query52	83	85	73	73
query53	263	285	205	205
query54	274	227	224	224
query55	77	70	64	64
query56	309	294	275	275
query57	1317	1275	1154	1154
query58	303	240	261	240
query59	1633	1594	1430	1430
query60	301	269	255	255
query61	163	149	152	149
query62	542	500	428	428
query63	240	202	206	202
query64	2799	1049	897	897
query65	4750	4666	4608	4608
query66	1821	505	380	380
query67	29383	29289	29151	29151
query68	3173	1545	972	972
query69	419	302	271	271
query70	1025	990	938	938
query71	374	342	319	319
query72	3058	2736	2402	2402
query73	866	801	431	431
query74	5050	4960	4746	4746
query75	2521	2510	2130	2130
query76	2352	1181	784	784
query77	352	378	282	282
query78	11766	11835	11413	11413
query79	2519	1115	760	760
query80	1723	566	456	456
query81	516	329	284	284
query82	597	156	120	120
query83	379	319	297	297
query84	305	160	135	135
query85	982	605	533	533
query86	416	292	288	288
query87	1832	1827	1753	1753
query88	3700	2808	2782	2782
query89	438	371	339	339
query90	1892	196	189	189
query91	198	189	162	162
query92	62	63	59	59
query93	1775	1537	943	943
query94	725	361	310	310
query95	783	525	492	492
query96	1062	789	371	371
query97	2603	2632	2466	2466
query98	215	205	201	201
query99	1090	1116	963	963
Total cold run time: 265547 ms
Total hot run time: 177428 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
ClickBench: Total hot run time: 25.12 s
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/clickbench-tools
ClickBench test result on commit 51c1f992647811ab0222edad2935131f445aaf33, data reload: false

query1	0.01	0.01	0.00
query2	0.10	0.05	0.05
query3	0.25	0.14	0.13
query4	1.61	0.13	0.13
query5	0.24	0.24	0.21
query6	1.22	1.10	1.06
query7	0.04	0.01	0.01
query8	0.06	0.04	0.04
query9	0.37	0.31	0.31
query10	0.56	0.58	0.55
query11	0.19	0.13	0.13
query12	0.18	0.14	0.14
query13	0.47	0.49	0.49
query14	1.02	1.02	1.01
query15	0.62	0.59	0.60
query16	0.34	0.32	0.31
query17	1.07	1.12	1.07
query18	0.23	0.22	0.21
query19	2.04	1.94	2.00
query20	0.01	0.01	0.01
query21	15.40	0.23	0.14
query22	4.82	0.06	0.06
query23	16.11	0.31	0.12
query24	2.98	0.44	0.32
query25	0.11	0.05	0.05
query26	0.72	0.20	0.14
query27	0.05	0.04	0.03
query28	3.54	0.94	0.53
query29	12.47	4.14	3.27
query30	0.28	0.15	0.16
query31	2.77	0.59	0.32
query32	3.22	0.58	0.48
query33	3.23	3.24	3.31
query34	15.71	4.24	3.55
query35	3.52	3.54	3.55
query36	0.55	0.45	0.42
query37	0.08	0.07	0.06
query38	0.06	0.04	0.04
query39	0.03	0.03	0.04
query40	0.18	0.16	0.16
query41	0.08	0.03	0.03
query42	0.03	0.02	0.02
query43	0.05	0.03	0.04
Total cold run time: 96.62 s
Total hot run time: 25.12 s

@hello-stephen

Copy link
Copy Markdown
Contributor

BE UT Coverage Report

Increment line coverage 74.31% (5978/8045) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 57.58% (24196/42025)
Line Coverage 41.46% (239339/577208)
Region Coverage 37.28% (189380/508053)
Branch Coverage 38.33% (84841/221340)

@hello-stephen

Copy link
Copy Markdown
Contributor

BE Regression && UT Coverage Report

Increment line coverage 81.57% (6546/8025) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 74.93% (30722/41000)
Line Coverage 59.27% (340032/573678)
Region Coverage 55.86% (284880/509946)
Branch Coverage 57.11% (126488/221482)

@Gabriel39

Copy link
Copy Markdown
Contributor Author

/review

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Request changes. I found three new issues in the native Parquet path: two P1 optional-index boundary failures (an unbounded serialized-index allocation and false-negative IS NULL pruning from contradictory null metadata) plus one P2 cache-disabled V2 level-copy regression.

Checkpoint summary:

  • Goal, scope, and tests: the Arrow-to-native materialization goal is coherent and the PR adds broad SerDe, decoder, nested-reader, scheduling, cache, compatibility, and profile coverage. The three inline cases still need focused fallback/correctness/performance tests.
  • Correctness and compatibility: I checked flat/nested, plain/dictionary, indexed/sequential, selected/skipped, page-crossing, strict/non-strict, old-writer, and compressed/uncompressed V2 paths. Existing cardinality, decoder, decimal, timestamp, and projection findings were deduplicated rather than repeated.
  • Concurrency, lifecycle, and observability: shared metadata/cache publication and cleanup/profile paths were reviewed. No additional distinct concurrency issue survived; the current lifecycle/profile threads remain applicable.
  • Configuration and performance: cache enable/disable and mapping/compatibility options were traced. The cache-disabled V2 copy and optional-index memory exposure are the new surviving performance/resource issues.
  • Transactions, writes, and FE/BE variable propagation: not applicable to this read-path change.
  • User focus: no additional focus was provided.

This was a static review as required by the runner contract; I did not build or run tests. All 134 authoritative changed paths were swept, and the independent full/risk reviews converged on this exact comment set with no further valuable findings.

Comment thread be/src/format_v2/parquet/parquet_file_context.cpp
Comment thread be/src/format_v2/parquet/parquet_statistics.cpp Outdated
Comment thread be/src/format_v2/parquet/reader/native/column_chunk_reader.cpp
@Gabriel39

Copy link
Copy Markdown
Contributor Author

run buildall

@Gabriel39

Copy link
Copy Markdown
Contributor Author

/review

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The native Parquet migration still has ten blocking correctness and robustness issues: malformed optional Bloom metadata can cause an out-of-bounds probe or multi-gigabyte allocation; schema child counts, unbounded schema depth, and row-group chunk cardinality can abort or exhaust the BE; split assignment can silently omit rows and prefetch planning can abort because both bypass the checked chunk-range contract; invalid logical/physical annotations reach fatal direct-consumer assertions; inconsistent footer null counts can falsely prune real rows; the first V1 nested page can silently discard orphan continuation values; and an unrelated Nereids golden-file edit has no changed producer.

Critical checkpoints: correctness/data integrity is blocked by the footer-statistics and logical-type cases; process safety/resource bounds is blocked by the Bloom/schema/prefetch cases; scanner lifecycle, lazy materialization, profile propagation, cache/IO integration, compatibility paths, and concurrency were reviewed with no additional non-duplicate findings beyond existing threads and this inline set. The new tests are broad but omit the malformed-metadata cases requested inline. Builds/tests were not run because this automated review environment explicitly prohibits them. The user supplied no additional focus beyond the complete review.

Existing review threads and replies were deduplicated before selecting these comments.

Convergence note: the tenth candidate was found and independently verified in the third and final configured review round. It is included below, but the three-round cap means this review cannot claim a subsequent same-set convergence pass.

Comment thread be/src/format_v2/parquet/parquet_statistics.cpp
Comment thread be/src/format_v2/parquet/parquet_scan.cpp Outdated
Comment thread be/src/format_v2/parquet/parquet_scan.cpp Outdated
Comment thread be/src/format_v2/parquet/native_schema_desc.cpp
Comment thread be/src/format_v2/parquet/reader/native/column_reader.cpp
Comment thread be/src/format_v2/parquet/parquet_statistics.cpp
Comment thread regression-test/data/nereids_rules_p0/pkfk/eliminate_inner.out Outdated
Comment thread be/src/format_v2/parquet/native_schema_desc.cpp
Comment thread be/src/format_v2/parquet/parquet_scan.cpp Outdated
Comment thread be/src/format_v2/parquet/reader/native/column_chunk_reader.cpp
@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-H: Total hot run time: 29774 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpch-tools
Tpch sf100 test result on commit 542e570c04802212a7ff4105eea505de9a5c734a, data reload: false

------ Round 1 ----------------------------------
============================================
q1	17874	4131	4086	4086
q2	2014	330	202	202
q3	10311	1462	841	841
q4	4689	485	342	342
q5	7494	850	582	582
q6	188	173	136	136
q7	763	830	627	627
q8	9405	1539	1578	1539
q9	5684	4424	4398	4398
q10	6750	1756	1487	1487
q11	513	354	329	329
q12	745	603	450	450
q13	18093	3451	2814	2814
q14	264	264	244	244
q15	q16	793	774	712	712
q17	985	951	1047	951
q18	6880	5735	5693	5693
q19	1297	1285	1072	1072
q20	831	668	586	586
q21	6066	2633	2378	2378
q22	437	359	305	305
Total cold run time: 102076 ms
Total hot run time: 29774 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	4448	4437	4410	4410
q2	300	331	215	215
q3	4723	4995	4428	4428
q4	2076	2194	1384	1384
q5	4483	4319	4355	4319
q6	235	177	127	127
q7	1977	2067	1648	1648
q8	2542	2245	2236	2236
q9	8116	8159	7795	7795
q10	4682	4637	4199	4199
q11	572	413	394	394
q12	765	746	539	539
q13	3372	3553	2961	2961
q14	305	307	275	275
q15	q16	728	735	649	649
q17	1374	1368	1369	1368
q18	8003	7582	7235	7235
q19	1200	1127	1074	1074
q20	2255	2214	1947	1947
q21	5342	4675	4500	4500
q22	510	447	407	407
Total cold run time: 58008 ms
Total hot run time: 52110 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 177413 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpcds-tools
TPC-DS sf100 test result on commit 542e570c04802212a7ff4105eea505de9a5c734a, data reload: false

query5	4349	648	509	509
query6	468	239	234	234
query7	4899	620	346	346
query8	349	192	174	174
query9	8795	4104	4073	4073
query10	478	350	315	315
query11	5856	2365	2151	2151
query12	159	109	108	108
query13	1299	620	438	438
query14	6236	5229	4881	4881
query14_1	4253	4203	4238	4203
query15	219	204	176	176
query16	989	497	466	466
query17	955	703	593	593
query18	2444	506	374	374
query19	202	185	147	147
query20	111	103	117	103
query21	227	153	134	134
query22	13562	13637	13308	13308
query23	17449	16551	16167	16167
query23_1	16284	16237	16244	16237
query24	7574	1755	1297	1297
query24_1	1321	1286	1283	1283
query25	531	435	367	367
query26	1330	351	217	217
query27	2591	603	381	381
query28	4477	2001	2043	2001
query29	1062	599	470	470
query30	343	275	224	224
query31	1121	1090	975	975
query32	109	61	60	60
query33	542	313	245	245
query34	1170	1165	646	646
query35	764	790	663	663
query36	1186	1183	1094	1094
query37	153	105	92	92
query38	1873	1654	1670	1654
query39	896	875	860	860
query39_1	852	865	842	842
query40	245	161	142	142
query41	67	64	65	64
query42	92	93	98	93
query43	321	325	277	277
query44	1418	764	753	753
query45	194	181	173	173
query46	1105	1191	721	721
query47	2088	2117	2014	2014
query48	411	413	301	301
query49	583	408	315	315
query50	1073	435	353	353
query51	10731	10844	10541	10541
query52	88	89	77	77
query53	266	278	203	203
query54	303	249	234	234
query55	76	73	69	69
query56	317	321	314	314
query57	1345	1292	1184	1184
query58	302	269	286	269
query59	1621	1644	1453	1453
query60	322	280	243	243
query61	154	149	144	144
query62	561	499	429	429
query63	242	210	203	203
query64	2820	1046	862	862
query65	4787	4657	4615	4615
query66	1827	506	381	381
query67	29334	29268	28558	28558
query68	3143	1578	947	947
query69	423	317	263	263
query70	1032	959	967	959
query71	374	317	307	307
query72	3063	2736	2364	2364
query73	824	776	449	449
query74	5065	4953	4698	4698
query75	2531	2521	2141	2141
query76	2320	1173	757	757
query77	348	365	289	289
query78	11925	11856	11324	11324
query79	1401	1102	750	750
query80	670	550	464	464
query81	477	335	295	295
query82	583	160	128	128
query83	401	327	300	300
query84	321	163	129	129
query85	946	596	561	561
query86	373	297	283	283
query87	1822	1823	1765	1765
query88	3725	2782	2763	2763
query89	429	381	331	331
query90	1938	208	196	196
query91	202	193	164	164
query92	63	59	59	59
query93	1676	1618	972	972
query94	538	346	315	315
query95	793	506	458	458
query96	1082	801	339	339
query97	2651	2608	2485	2485
query98	224	216	200	200
query99	1086	1099	965	965
Total cold run time: 262998 ms
Total hot run time: 177413 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
ClickBench: Total hot run time: 24.98 s
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/clickbench-tools
ClickBench test result on commit 542e570c04802212a7ff4105eea505de9a5c734a, data reload: false

query1	0.01	0.01	0.01
query2	0.09	0.08	0.04
query3	0.25	0.14	0.14
query4	1.61	0.15	0.14
query5	0.25	0.24	0.24
query6	1.24	1.08	1.06
query7	0.04	0.01	0.00
query8	0.05	0.04	0.03
query9	0.39	0.32	0.33
query10	0.54	0.54	0.55
query11	0.19	0.13	0.14
query12	0.18	0.15	0.14
query13	0.47	0.47	0.49
query14	1.00	1.02	1.01
query15	0.62	0.60	0.59
query16	0.30	0.31	0.34
query17	1.10	1.13	1.10
query18	0.23	0.20	0.22
query19	2.09	1.94	1.98
query20	0.02	0.02	0.01
query21	15.46	0.18	0.12
query22	5.01	0.06	0.05
query23	16.12	0.31	0.12
query24	3.00	0.44	0.32
query25	0.10	0.05	0.04
query26	0.75	0.21	0.14
query27	0.04	0.03	0.04
query28	3.50	0.91	0.53
query29	12.48	4.12	3.30
query30	0.27	0.16	0.16
query31	2.76	0.59	0.31
query32	3.22	0.59	0.49
query33	3.18	3.13	3.30
query34	15.70	4.23	3.50
query35	3.55	3.52	3.53
query36	0.55	0.45	0.42
query37	0.09	0.07	0.06
query38	0.05	0.04	0.04
query39	0.04	0.03	0.03
query40	0.19	0.17	0.15
query41	0.09	0.03	0.03
query42	0.04	0.03	0.03
query43	0.04	0.04	0.04
Total cold run time: 96.9 s
Total hot run time: 24.98 s

@Gabriel39

Copy link
Copy Markdown
Contributor Author

run buildall

@Gabriel39

Copy link
Copy Markdown
Contributor Author

/review

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-H: Total hot run time: 29294 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpch-tools
Tpch sf100 test result on commit f1764a78336a1d3ac56556aee691130d1b5f54c1, data reload: false

------ Round 1 ----------------------------------
============================================
q1	17656	4192	4371	4192
q2	2041	330	193	193
q3	10246	1492	835	835
q4	4702	470	344	344
q5	7542	838	569	569
q6	189	182	139	139
q7	754	815	613	613
q8	9840	1593	1515	1515
q9	5823	4362	4381	4362
q10	6896	1724	1472	1472
q11	508	362	329	329
q12	755	570	457	457
q13	18062	3294	2702	2702
q14	271	260	242	242
q15	q16	790	786	702	702
q17	1039	862	974	862
q18	6880	5648	5522	5522
q19	1388	1363	957	957
q20	823	665	624	624
q21	5773	2659	2367	2367
q22	423	358	296	296
Total cold run time: 102401 ms
Total hot run time: 29294 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	4490	4413	4390	4390
q2	275	319	212	212
q3	4593	4948	4359	4359
q4	2060	2158	1365	1365
q5	4405	4292	4272	4272
q6	231	176	128	128
q7	1779	2073	1723	1723
q8	2490	2190	2293	2190
q9	7857	7849	7736	7736
q10	4715	4644	4197	4197
q11	599	415	373	373
q12	731	742	552	552
q13	3478	3649	3007	3007
q14	299	291	284	284
q15	q16	734	740	652	652
q17	1362	1353	1337	1337
q18	8116	7394	6779	6779
q19	1122	1053	1057	1053
q20	2204	2190	1958	1958
q21	5725	4588	4443	4443
q22	535	465	405	405
Total cold run time: 57800 ms
Total hot run time: 51415 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 177253 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpcds-tools
TPC-DS sf100 test result on commit f1764a78336a1d3ac56556aee691130d1b5f54c1, data reload: false

query5	4340	630	500	500
query6	465	237	224	224
query7	4903	605	345	345
query8	342	194	166	166
query9	8816	4105	4085	4085
query10	493	366	310	310
query11	5953	2321	2130	2130
query12	158	107	104	104
query13	1285	614	455	455
query14	6566	5261	4903	4903
query14_1	4248	4254	4249	4249
query15	209	209	180	180
query16	1026	511	455	455
query17	1138	703	578	578
query18	2593	475	360	360
query19	211	197	154	154
query20	117	110	107	107
query21	237	158	134	134
query22	13600	13534	13611	13534
query23	17805	16772	16436	16436
query23_1	16273	16170	16250	16170
query24	7572	1785	1269	1269
query24_1	1324	1325	1290	1290
query25	571	459	393	393
query26	1348	375	220	220
query27	2465	613	386	386
query28	4448	2002	1992	1992
query29	1079	634	498	498
query30	345	264	229	229
query31	1121	1103	981	981
query32	111	67	70	67
query33	549	333	249	249
query34	1162	1151	640	640
query35	767	776	661	661
query36	1183	1181	1055	1055
query37	155	110	91	91
query38	1872	1692	1668	1668
query39	881	865	850	850
query39_1	845	838	834	834
query40	257	171	188	171
query41	64	62	62	62
query42	95	94	96	94
query43	322	325	280	280
query44	1438	776	765	765
query45	194	191	179	179
query46	1045	1185	715	715
query47	2148	2087	1950	1950
query48	406	428	279	279
query49	583	413	315	315
query50	1064	432	336	336
query51	10640	10856	10338	10338
query52	86	87	83	83
query53	267	275	209	209
query54	290	235	234	234
query55	76	69	69	69
query56	315	297	295	295
query57	1322	1303	1186	1186
query58	274	261	252	252
query59	1600	1693	1483	1483
query60	305	272	252	252
query61	148	148	148	148
query62	538	493	438	438
query63	237	203	211	203
query64	2851	1101	889	889
query65	4634	4667	4642	4642
query66	1828	548	383	383
query67	29286	28565	29040	28565
query68	3195	1525	881	881
query69	403	294	272	272
query70	1037	1012	931	931
query71	403	326	312	312
query72	2994	2672	2311	2311
query73	825	778	425	425
query74	5061	4921	4739	4739
query75	2529	2479	2147	2147
query76	2333	1177	762	762
query77	347	377	287	287
query78	11932	11828	11256	11256
query79	2615	1152	752	752
query80	1751	550	473	473
query81	552	330	287	287
query82	606	155	123	123
query83	374	338	306	306
query84	279	159	134	134
query85	969	625	519	519
query86	420	295	274	274
query87	1838	1821	1756	1756
query88	3733	2792	2753	2753
query89	452	373	325	325
query90	1899	199	206	199
query91	201	194	166	166
query92	64	61	54	54
query93	1851	1460	981	981
query94	725	360	308	308
query95	821	493	554	493
query96	1082	791	379	379
query97	2694	2625	2483	2483
query98	213	204	198	198
query99	1089	1108	989	989
Total cold run time: 266504 ms
Total hot run time: 177253 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
ClickBench: Total hot run time: 25.13 s
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/clickbench-tools
ClickBench test result on commit f1764a78336a1d3ac56556aee691130d1b5f54c1, data reload: false

query1	0.01	0.01	0.00
query2	0.09	0.04	0.05
query3	0.26	0.14	0.14
query4	1.61	0.14	0.14
query5	0.25	0.23	0.22
query6	1.25	1.09	1.04
query7	0.04	0.01	0.00
query8	0.06	0.04	0.04
query9	0.39	0.32	0.32
query10	0.58	0.56	0.54
query11	0.20	0.13	0.13
query12	0.18	0.14	0.15
query13	0.49	0.48	0.49
query14	1.03	1.03	1.01
query15	0.62	0.62	0.60
query16	0.32	0.33	0.33
query17	1.09	1.10	1.09
query18	0.22	0.20	0.20
query19	2.03	1.90	2.01
query20	0.02	0.02	0.02
query21	15.40	0.22	0.15
query22	4.89	0.06	0.05
query23	16.16	0.33	0.12
query24	2.98	0.39	0.33
query25	0.11	0.05	0.04
query26	0.73	0.23	0.14
query27	0.04	0.04	0.04
query28	3.56	0.91	0.53
query29	12.47	4.17	3.30
query30	0.28	0.19	0.16
query31	2.78	0.60	0.31
query32	3.22	0.58	0.49
query33	3.17	3.22	3.16
query34	15.69	4.25	3.58
query35	3.53	3.57	3.54
query36	0.57	0.45	0.41
query37	0.10	0.07	0.07
query38	0.05	0.05	0.04
query39	0.04	0.02	0.02
query40	0.19	0.17	0.17
query41	0.08	0.03	0.03
query42	0.04	0.03	0.03
query43	0.04	0.04	0.04
Total cold run time: 96.86 s
Total hot run time: 25.13 s

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Request changes. After deduplicating all 80 existing inline comments, this review found six new P1 correctness/compatibility failures and one P2 profiling defect in the native FileScannerV2 Parquet path.

Critical checkpoint conclusions:

  • Goal and scope: the Arrow-to-native decode/materialization direction is coherent, but the full 145-file change is not yet safe to merge because valid or malformed Parquet metadata can still abort the BE, select the wrong schema/page layout, or return wrong values.
  • Correctness and error handling: the blocking cases are the obsolete raw page-cache range assertion, missing PageHeader and SchemaElement discriminant validation, and a 32-bit DELTA padding-cursor wrap. External file metadata must return a checked error rather than assert or silently shift the decoder cursor.
  • Compatibility and schema inference: valid ENUM/BSON leaves regress from STRING to VARBINARY, and valid logical TIME(MILLIS/MICROS) is inferred as TIMEV2(0), hiding fractional precision.
  • Architecture and maintainability: the native trust-boundary validators need to own the file-format invariants before downstream decoders consume generated Thrift defaults; duplicated schema mapping should remain aligned with the established resolver.
  • Concurrency and lifecycle: cache publication, row-group reader ownership, periodic profile flushing, close/reset, and merge-reader lifetime were rechecked; no additional non-duplicate race, deadlock, use-after-free, or lost additive profile delta survived review.
  • Performance and observability: the native/direct-materialization design targets the intended CPU and memory reductions, but PageCrossingBatches is currently reconstructed per 16-batch profile flush and per column, so it cannot be compared with per-batch TotalBatches as documented.
  • Tests and validation: changed tests are broad but omit the seven inline boundary cases. This was a static review as required by the runner contract; no local build or tests were run. Current CI has compile/style/license/performance and vault checks passing, Linux BE UT/regressions still pending, and the macOS BE UT job failed at setup because the runner supplied Java 25 while the workflow requires JDK 17.
  • User focus: no additional focus was supplied, so the complete authoritative patch, mandatory design docs, existing threads, parallel paths, and error/resource boundaries were reviewed.

All three final-round agents independently returned NO_NEW_VALUABLE_FINDINGS for this exact seven-comment set at head f1764a7.

DORIS_CHECK(leaf_column_id >= 0 &&
leaf_column_id < static_cast<int>(row_group_metadata.columns.size()));
const auto& column_metadata = row_group_metadata.columns[leaf_column_id].meta_data;
const int64_t offset = column_metadata.__isset.dictionary_page_offset

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Remove or validate this obsolete page-cache range traversal The new metadata-safety test deliberately permits an optional dictionary_page_offset = -1 by falling back to the valid data-page offset in build_native_prefetch_ranges(). This separate open-time helper instead selects the set dictionary offset unconditionally and DORIS_CHECKs it, so enabling the Parquet page cache turns that same file into a BE abort. register_page_cache_ranges() now discards the result because native readers cache exact pages, so remove this traversal or reuse the checked chunk-range helper and propagate a Status rather than asserting on file metadata.

}
} else if (logicalType.__isset.FLOAT16) {
ans.first = DataTypeFactory::instance().create_data_type(TYPE_FLOAT, nullable);
} else {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Preserve STRING inference for ENUM and BSON leaves This mapper omits logical ENUM/BSON, and the converted-type overload omits their legacy annotations too. Both cases therefore throw into get_doris_type()'s BYTE_ARRAY fallback; V2 enables varbinary mapping, so valid ENUM/BSON columns are now exposed as VARBINARY. The established parquet_type.cpp resolver and this native decoder both classify these annotations as STRING. Handle ENUM/BSON alongside STRING/JSON in both overloads and cover valid annotated leaves, not only the invalid ENUM-group case.

}
}
} else if (logicalType.__isset.TIME) {
ans.first = DataTypeFactory::instance().create_data_type(TYPE_TIMEV2, nullable);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Derive TIMEV2 scale from the Parquet time unit The factory default here is scale 0, while valid logical TIME(MILLIS/MICROS) carries fractional precision and the native decoder preserves that unit and materializes microseconds. The established parquet_type.cpp resolver reports TIMEV2(3) and TIMEV2(6); returning TIMEV2(0) from the new inferred schema suppresses those fractional digits at serialization. Map the unit to the same scale and add inferred-schema/value coverage for both units.

COUNTER_UPDATE(_profile.native_page_fragments, page_fragments);
}
// Summed fragments from MAP/STRUCT siblings do not mean any individual leaf crossed a page.
if (max_leaf_page_reads > 1 && _profile.page_crossing_batches != nullptr) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Count page crossings at the scheduler batch boundary flush_profile() runs only every 16 scheduler batches (or at the row-group tail), so max_leaf_page_reads > 1 describes an amortized interval, not one batch. Sixteen batches that each open one page become one false crossing, sixteen real crossings become one, and each projected top-level column can increment the same shared counter. This makes PageCrossingBatches incomparable with per-batch TotalBatches as documented. Record/OR a crossing flag for each scheduler batch and keep the periodic flush only for additive cumulative statistics.

// Sizes are untrusted signed Thrift fields and must fit the column chunk before arithmetic.
return Status::Corruption("Parquet page payload exceeds its column chunk");
}
if (_cur_page_header.__isset.data_page_header_v2) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Validate the page-type discriminant before choosing a layout PageHeader.type is the contract that identifies which single page-specific header is set, but this validation and is_header_v2() choose V2 solely from __isset.data_page_header_v2. A DATA_PAGE_V2 carrying only a V1 member is decoded as V1, a DATA_PAGE carrying a V2 member is decoded as V2, and absent/dual members are not rejected before level, compression, and payload cursors are selected. Require the matching member (and reject competing members) for each page type, with malformed swapped/absent/dual-header tests.


const size_t depth = pending.back().depth + 1;
--pending.back().remaining_children;
const int children = num_children_node(schemas[pos]);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Validate SchemaElement kind and repetition before parsing This pass bounds num_children, but it never enforces the Parquet contract that groups set num_children and no type, primitives set type and no num_children, and every non-root node sets repetition_type. With neither kind field, the node is treated as a leaf and the generated default type (BOOLEAN) is consumed; with no repetition bit it is treated as REQUIRED. For an optional Page V1 leaf that can leave definition-level bytes at the value cursor instead of returning corruption. Validate these isset invariants here before building the tree and add missing/dual-kind plus missing-repetition footer tests.

_total_values_remaining -= num_values;

if (_total_values_remaining == 0) [[unlikely]] {
if (!_bit_reader->Advance(_delta_bit_width * _values_remaining_current_mini_block)) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Widen the final miniblock padding calculation The multiplication occurs in uint32_t before the result reaches Advance(int64_t). For example, block size 134217856 with one miniblock, two values, and width 32 requires skipping 4,294,971,360 bits after the second value, but this expression wraps to 4,064 bits. That block still fits the signed page-size domain; in DELTA_LENGTH_BYTE_ARRAY the shared locator is then 512 MiB early and returns padding as string payload. Use checked uint64/int64 multiplication, verify it fits the remaining stream, and cover the overflow boundary plus the byte-array cursor handoff.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants